/* 
 * 	$Id: DumbPlayer.java,v 1.3 2007/11/14 22:04:58 johnc Exp $
 * 
 * 	Programming and Problem Solving
 *  Copyright (c) 2007 The Trustees of Columbia University
 */
package explorandum.f09.g5;

import java.awt.Color;
import java.awt.Point;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Random;

import explorandum.Logger;
import explorandum.Move;
import explorandum.Player;
import explorandum.GameConstants;
import explorandum.g2.map.Node;
import explorandum.g2.type.HPoint;

import java.util.*;

public class G5Player implements Player {
	
	private static final Boolean followFeatures  = true;
	private static final Boolean displayOpenness = false;
	public Point[] visited;
	int count;
	Boolean useFramework = true; 
	Logger log;
	Random rand;
	Map map;
  int range;
  int num_explorers;
  int num_rounds;
	int previous_explore_direction = 1;
  OpenShortestPath sp;
  Point current_location;
  Point loc1 = new Point(5,3);
  Point loc2 = new Point(2,2);
  Point loc3 = new Point(4,6);
  int d_init = 6;
  /*In the event that we want to employ a metaStrategy for an explicitly
   * set number of moves, we'll use this counter to keep track of how many 
   * moves have passed since tne metaStrategy was employed
   * 
   * No logic uses this right now, so its not used anywhere
   * else in the code. Hopefully we wont need to use it 
   * but its here just in case
  */
  int moveCounter = 0;
  int dcounter = 0;
  int explorerId;
  /*Flags to distinguish between different strategies. Every
   *time want to try a new strategy, we need to include the
   *a flag in this list to identify the new strategy by.
   */
  public static enum Strategy{STAND_STILL, EXPLORE_FOR_WATER_AND_OPEN_SPACE, 
	  EXPLORE_NULL_CELLS,EXPLORE_LOCAL_AREA,COASTHUGGING};

  /*This will kkeep the integer values which represent
   * the ranks for each of the strategies we come up with
   */
  HashMap<Strategy, Integer> RanksForStrategies = new HashMap<Strategy, Integer>();

  public void register(int _explorerID, int rounds, int explorers, int _range,
			Logger _log, Random _rand) 
	{
		explorerId = _explorerID;
		log = _log;
		rand = _rand;
		map = new MapInHash();
		range = _range;
		num_explorers = explorers;
		num_rounds = rounds;
		sp = new OpenShortestPath(map, range);
		map.setNumRound(num_rounds);
		log.debug("\nRounds:" + rounds + "\nExplorers:" + explorers
				+ "\nRange:" + range);
		
		if(useFramework) // Part of framwork code
			initializeRankHash();
	}
  
  	public void initializeRankHash()
  	{
  		Strategy[] values = Strategy.values();
  		
  		for(int i = 0; i < values.length;i++)
  		{
  			Strategy s = values[i];
  			switch(s)
  			{
  				case STAND_STILL:
  					RanksForStrategies.put(s, i);
  					break;
  				case EXPLORE_FOR_WATER_AND_OPEN_SPACE:
  					RanksForStrategies.put(s, i);
  					break;
  				case EXPLORE_NULL_CELLS:
  					RanksForStrategies.put(s, i);
  					break;
  				case EXPLORE_LOCAL_AREA:
  					RanksForStrategies.put(s, i);
  					break;
  				case COASTHUGGING:
  					RanksForStrategies.put(s, i);
  					break;  				
  			}
  		}
  	}
  	
  	public ArrayList<Strategy> getPossibleStrategies(Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[][] otherExplorers,
			Integer[] terrain, int time,Boolean StepStatus) {
  		
  		ArrayList<Strategy> list = new ArrayList<Strategy>();
  		if(time < 2)
  		{
  			boolean sameStart = sameCellStart(offsets, otherExplorers);

  			//System.out.println(sameStart);
  			if(sameStart)
  			{

  				list.add(Strategy.STAND_STILL);
  			}

  		}
  		else if ((((double) time) / num_rounds < 0.65) || dcounter > 0)
  		{
  			list.add(Strategy.EXPLORE_FOR_WATER_AND_OPEN_SPACE);
  		}

  		else if ((((double) time) / num_rounds < 0.75) || dcounter>0)
  		{
  			list.add(Strategy.EXPLORE_NULL_CELLS);
  		}
  		else
  		{
  			list.add(Strategy.EXPLORE_LOCAL_AREA);
  		}
  		
  		/* Also list possible checks that we want to do */
  		((MapInHash)map).guessClaimedFeatures(currentLocation, range);

  		return list;
  	}



	public Color color() throws Exception {
		return new Color(160,32,240);
	}

  // This function implements the boundary tracing algorithm. It tries all 8
  // directions and find the one that have the large openness value. Openness
  // is defined as:
  //   - Near to many unexplored cells.
  //   - Near to many unexplored water.
  //   - NOT near mountains.
  //   - NOT near explored cells.
  // This function returns -1 if all nearby cells are visited.
  public int explore(int minimum_score) {
    double neighbor_scores[] = new double[9];
    double pre_mod_neighbors[] = new double[9];
    double direction_compensate[] = {1, 1, 1, 1, 1};
    DecimalFormat format = new DecimalFormat("0.00");
    ArrayList<Cell> borders = null;
    
    /* new Fall 2009 code
     * 
     * Follow Features is a strategy that gives neighbor cells that also border the same
     *   feature as the current cell a bonus.  This is meant to mimic pure "Coast Hugging"
     *   behavior while staying in the Openness function system.
     */
    if(followFeatures)
    {
    	 ArrayList<Cell> neighbors = map.getImmediateNeighbors(current_location);
    	 borders = new ArrayList<Cell>();
    	 for(Cell neighbor : neighbors) {
    		 if(neighbor != null && neighbor.terrain != GameConstants.LAND) {
    			 borders.add(neighbor);
    		 }
    	 }
    }

    // Test each direction and find the best one.
    int best_direction = 0;
    double best_score = 0;
    for (int i = 1; i <= 8; i++) {
      Point neighbor_point = map.getNeighborPoint(current_location, i);
      // Measure the openness of nearby cells.
      double openness = map.getCellOpenness(neighbor_point, range);
      if(followFeatures || displayOpenness) {
    	  pre_mod_neighbors[i] = Double.valueOf(format.format(openness));
      }
      
      openness *= direction_compensate[
        Math.abs((previous_explore_direction - i + 12) % 8 - 4)];
      if (i % 2 == 0)
        openness /= 2;

      // Measure how good this direction is. It make the player keep turning
      // right whenever possible.
      double direction_score = (i - (previous_explore_direction + 3) + 16) % 8;

      // The final score is the combination of the openness and the direction
      // score.
      neighbor_scores[i] = ((int) (openness)) * 10 + direction_score;
      Util.debugMessage("explore", "explore score for direction " + i + " is " + neighbor_scores[i]);
      
      /* New Fall 2009 Code
       * 
       *   So if we're doing the "follow feature" strategy and current cell does border a feature,
       *     if for any neighbor that borders the same feature, provide a multiplicative bonus.
       */
      if(followFeatures && borders != null && borders.size() != 0)
      {
    	  /* No need to check neighbors if borders nothing */
    	  ArrayList<Cell> neighbor_neighbors = map.getImmediateNeighbors(neighbor_point);
    	  for(Cell my_bordered_feature : borders)
    	  {
    		  if(neighbor_neighbors.contains(my_bordered_feature)) {
    			  /* this is a coastline, do a multiplier */
    			  if(pre_mod_neighbors[i] != 0) {
    				  /* magic number pulled out from a few test cases that is necessary to overcome
    				   *   the inherent preference for null areas
    				   */
    				  neighbor_scores[i] *= 15;
    			  }
    			  break;
    		  }
    	  }
      }
      
      if (neighbor_scores[i] > best_score) {
        best_score = neighbor_scores[i];
        best_direction = i;
      }
    }
    
    /*
     * New Fall 2009 Code
     * 
     * Helper debug function that prints the 8 openness values in a nice matrix form.
     */
    if (displayOpenness) {
    	System.out.print("___ " + neighbor_scores[GameConstants.NORTHWEST] + " (" + pre_mod_neighbors[GameConstants.NORTHWEST]+ ")");
    	System.out.print("___ " + neighbor_scores[GameConstants.NORTH] + " (" + pre_mod_neighbors[GameConstants.NORTH]+ ")");
    	System.out.print("___ " + neighbor_scores[GameConstants.NORTHEAST] + " (" + pre_mod_neighbors[GameConstants.NORTHEAST]+ ") ___\n");
    	
    	System.out.print("___ " + neighbor_scores[GameConstants.WEST] + " (" + pre_mod_neighbors[GameConstants.WEST]+ ")\t");
    	System.out.print("___ !!" + this.current_location.toString() + "!!");
    	System.out.print("___ " + neighbor_scores[GameConstants.EAST] + " (" + pre_mod_neighbors[GameConstants.EAST]+ ") ____\n");
    	
    	System.out.print("___ " + neighbor_scores[GameConstants.SOUTHWEST] + " (" + pre_mod_neighbors[GameConstants.SOUTHWEST]+ ")");
    	System.out.print("___ " + neighbor_scores[GameConstants.SOUTH] + " (" + pre_mod_neighbors[GameConstants.NORTHWEST]+ ")");
    	System.out.print("___ " + neighbor_scores[GameConstants.SOUTHEAST] + " (" + pre_mod_neighbors[GameConstants.SOUTHEAST]+ ") ___\n\n");
    	System.out.println("==============================================================\n");
    }
    

    Util.debugMessage("explore", "explore chooses " + best_direction + ", score is " + best_score);
    if (best_score >= minimum_score) {
      previous_explore_direction = best_direction;
      return best_direction;
    } else {
      return -1;
    }
  }

  boolean sameCellStart(Point[] offsets, Integer[][] otherExplorers){
	  for(int i=0; i<offsets.length; i++){
		  Point p = offsets[i];
		  if(p.x == 0 && p.y==0){
			  if(otherExplorers[i].length == num_explorers)
				  return true;
		  }
	  }
	  return false;
	  
  }
  
  boolean check_loop(Point[] p,int time){
	  for(int k=1;k<=20 && 2*k<=time;k++){  //k<=20, because we will detect cycles of length atmost 20. 2*k <= time, because those many rounds needed to decide
		  boolean cycle = true; // Check if last k elements are repeated.
		  for(int i=time-k;i<time;i++){
			  if(p[i]!= p[i-k]){
				  cycle = false;
				  break;
			  }
			  if(cycle) return true;
		  }
	  }
	  return false;
  }
  
	public Move move(Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[][] otherExplorers,
			Integer[] terrain, int time,Boolean StepStatus) 
	{
		try 
		{
			if(!useFramework) // Begin NonFramework code
			{

				if(time < 2)
				{

					boolean sameStart = sameCellStart(offsets, otherExplorers);

					//System.out.println(sameStart);
					if(sameStart)
					{

						return(new Move(GameConstants.STAYPUT));
					}
				}

				 visited[count] = currentLocation; 
				    	count++;
				    	boolean cycle = check_loop(visited,time); 
				    	if(cycle){
				    		System.out.println("Cycle !!!\n\n Cycle !!!\n");
				    		dcounter = d_init; // have used the same logic as syn diego had used to free a deadlock situation. it probably needs to be recoded.
				    		d_init += 6;
				    	}


				Util.debugMessage("move", "move at time " + time);
				current_location = currentLocation;
				loc3 = loc2;
				loc2 = loc1;
				loc1 = currentLocation;
				if(loc3.x == loc1.x && loc3.y == loc1.y)
				{
					Util.debugMessage("move", "deadlock!");
					dcounter = d_init;
					d_init += 6;
				}
				map.setTime(time);
				map.add(explorerId, currentLocation, offsets, hasExplorer, otherExplorers, terrain,
						time, range,StepStatus);
				
			    ((MapInHash)map).guessClaimedFeatures(currentLocation, range);
			    
				// === Game stage 1 - Explore (prefer water and open spaces) ===
				if ((((double) time) / num_rounds < 0.65) && dcounter==0) {
					// Call explore function for the boundary tracing algorithm.
					int direction = explore(60);
					if (direction >= 0)
						return new Move(ACTIONS[direction]);
					else {  // explore function get stuck
						Util.debugMessage("move", "local score too low");
						int direction_to_target = getDirectionToOpenSpace();
						if (direction_to_target > 0)
							return new Move(ACTIONS[direction_to_target]);
					}
					// === Game stage 2 - Go to null cells ===
				} else if ((((double) time) / num_rounds < 0.75) || dcounter>0) {
					dcounter--;
					int direction_to_target = getDirectionToOpenSpace();
					if (direction_to_target > 0)
						return new Move(ACTIONS[direction_to_target]);
					// === Game stage 3 - Explore (prefer local area) ===
				} else {
					// Call explore function for the boundary tracing algorithm.
					int direction = explore(10);
					if (direction >= 0)
						return new Move(ACTIONS[direction]);
					else {  // explore function get stuck
						int direction_to_target = getDirectionToOpenSpace();
						if (direction_to_target > 0)
							return new Move(ACTIONS[direction_to_target]);
					}
				}


				// Use random direction if all above approaches don't work.
				Util.debugMessage("move", "use random move");
				int random_direction = 0;
				int count = 0;
				while(true) {
					count++;
					if (count > 1000)
						break;
					random_direction = rand.nextInt(7) + 1;  
					Cell next = map.getCell(
							currentLocation.x + GameConstants._dx[random_direction],
							currentLocation.y + GameConstants._dy[random_direction]);
					if (next == null || (next.terrain == 0 &&  !(next.location.x == loc2.x && next.location.y == loc2.y)))
						break;
				}

				return new Move(ACTIONS[random_direction]);
			}//End of Nonframework Code
			else //Begin Framework code
			{
				Util.debugMessage("move", "move at time " + time);
				current_location = currentLocation;
				loc3 = loc2;
				loc2 = loc1;
				loc1 = currentLocation;
				if(loc3.x == loc1.x && loc3.y == loc1.y)
				{
					Util.debugMessage("move", "deadlock!");
					dcounter = d_init;
					d_init += 6;
				}
				map.setTime(time);
				map.add(explorerId, currentLocation, offsets, hasExplorer, otherExplorers, terrain,
						time, range,StepStatus);

				ArrayList<Strategy> possibleStrategies = getPossibleStrategies(currentLocation, offsets,
						hasExplorer, otherExplorers,
						terrain, time,StepStatus);

				rerankStrategies(currentLocation, offsets,
						hasExplorer, otherExplorers,
						terrain, time,StepStatus);

				Strategy s = pickBestStrategy(possibleStrategies);

				return executeStrategy(currentLocation, offsets,
						hasExplorer, otherExplorers,
						terrain, time,StepStatus, s);
			}// End Framework code

		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		return null;
	}
		

  public int getDirectionToOpenSpace() {
    sp.updateShortestPath(current_location);
    
    // Find null targets
    ArrayList<Cell> candidate_targets = endGameTargets();
    for (Cell target_cell : candidate_targets) {
      Util.debugMessage("move", "try target at " + target_cell.location);
      ArrayList<Cell> path =
        sp.getShortestDistancePath(target_cell.location);
      if (path != null && path.size() > 0) {
        Util.debugMessage("move", "go to target at " + target_cell.location);
        Point next = path.get(0).location;
        int direction_to_target = map.getDirection(current_location, next);
        return direction_to_target;
      }
    }

    // Find unstepped cell targets
    candidate_targets = findUnsteppedCellTarget();
    for (Cell target_cell : candidate_targets) {
      Util.debugMessage("move", "try unstepped target at " + target_cell.location);
      ArrayList<Cell> path =
        sp.getShortestDistancePath(target_cell.location);
      if (path != null && path.size() > 0) {
        Util.debugMessage("move", "go to unstepped target at " + target_cell.location);
        Point next = path.get(0).location;
        int direction_to_target = map.getDirection(current_location, next);
        return direction_to_target;
      }
    }

    return 0;
  }
  
  public void rerankStrategies(Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[][] otherExplorers,
			Integer[] terrain, int time,Boolean StepStatus)
			{
	  			/*This needs to be recoded badly
	  			but I cant think of a good way
	  			to do this besides trading ranks
	  			
	  			These are basically dummy if statements.
	  			Nothing is really reranked as of right now
	  			
	  			To add a new check for ranking, add an
	  			if statement at the end of this function which
	  			checks the parameter you want to check, and appropriately
	  			trade ranks with another Strategy
				(ranks are assigned incrementally right now)
				incrementally from 0 to whatever the length
				of the Strategy enumeration in method
				initializeRankHash.
				*/
	  			
	  			if(time < 2)
	  			{
	  				//Set to a rank of 0
	  				Integer temp = RanksForStrategies.put(Strategy.STAND_STILL,0);
	  			}
				else if (((double) time) / num_rounds < 0.65 || dcounter>0)
				{
					Integer temp = RanksForStrategies.put(Strategy.EXPLORE_FOR_WATER_AND_OPEN_SPACE,0);
					RanksForStrategies.put(Strategy.STAND_STILL, temp);
				}
				
				else if ((((double) time) / num_rounds < 0.75) || dcounter>0)
				{
					Integer temp = RanksForStrategies.put(Strategy.EXPLORE_NULL_CELLS,0);
					RanksForStrategies.put(Strategy.STAND_STILL, temp);
					
				}
				else
				{
					Integer temp = RanksForStrategies.put(Strategy.EXPLORE_LOCAL_AREA,0);
					RanksForStrategies.put(Strategy.STAND_STILL, temp);
				}
			}
  
  public Strategy pickBestStrategy(ArrayList<Strategy> possibleStrategies)
  {
	  Integer minRank = 9999999;
	  Integer minIndex = 0;
	  Strategy s;
	  
	  if(possibleStrategies.size()>1)
	  {
		  for(int i = 0; i < possibleStrategies.size(); i++)
		  {
			Strategy tempStrategy = possibleStrategies.get(i);
			Integer tempRank = RanksForStrategies.get(tempStrategy);
			if(tempRank< minRank)
			{
				minRank = tempRank;
				minIndex = i;
			}
		  }
		  s = possibleStrategies.get(minIndex);
	  }
	  else
		  s = possibleStrategies.get(0);
	  
	  return s;
  }
  
  public Move executeStrategy(Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[][] otherExplorers,
			Integer[] terrain, int time,Boolean StepStatus,Strategy s)
  {
	  switch(s)
	  {
	  case STAND_STILL:
		  return(new Move(GameConstants.STAYPUT));
	  case EXPLORE_FOR_WATER_AND_OPEN_SPACE:
		  int direction = explore(60);
		  if (direction >= 0)
			  return new Move(ACTIONS[direction]);
		  else 
		  {  // explore function get stuck
			  Util.debugMessage("move", "local score too low");
			  int direction_to_target = getDirectionToOpenSpace();
			  if (direction_to_target > 0)
				  return new Move(ACTIONS[direction_to_target]);
			  else
			  {
				  Util.debugMessage("move", "use random move");
				  int random_direction = 0;
				  int count = 0;
				  while(true) {
					  count++;
					  if (count > 1000)
						  break;
					  random_direction = rand.nextInt(7) + 1;  
					  Cell next = map.getCell(
							  currentLocation.x + GameConstants._dx[random_direction],
							  currentLocation.y + GameConstants._dy[random_direction]);
					  if (next == null || (next.terrain == 0 &&  !(next.location.x == loc2.x && next.location.y == loc2.y)))
						  break;
				  }

				  return new Move(ACTIONS[random_direction]);

			  }

		  }
	  case EXPLORE_NULL_CELLS:
		  dcounter--;
		  int direction_to_target = getDirectionToOpenSpace();
		  if (direction_to_target > 0)
			  return new Move(ACTIONS[direction_to_target]);
		  else
		  {
			  Util.debugMessage("move", "use random move");
			  int random_direction = 0;
			  int count = 0;
			  while(true) {
				  count++;
				  if (count > 1000)
					  break;
				  random_direction = rand.nextInt(7) + 1;  
				  Cell next = map.getCell(
						  currentLocation.x + GameConstants._dx[random_direction],
						  currentLocation.y + GameConstants._dy[random_direction]);
				  if (next == null || (next.terrain == 0 &&  !(next.location.x == loc2.x && next.location.y == loc2.y)))
					  break;
			  }

			  return new Move(ACTIONS[random_direction]);
		  }
	  case EXPLORE_LOCAL_AREA:
		  int directionToGo = explore(10);
		  if (directionToGo >= 0)
			  return new Move(ACTIONS[directionToGo]);
		  else {  // explore function get stuck
			  int direction_of_target = getDirectionToOpenSpace();
			  if (direction_of_target > 0)
				  return new Move(ACTIONS[direction_of_target]);

			  else
			  {
				  Util.debugMessage("move", "use random move");
				  int random_direction = 0;
				  int count = 0;
				  while(true) {
					  count++;
					  if (count > 1000)
						  break;
					  random_direction = rand.nextInt(7) + 1;  
					  Cell next = map.getCell(
							  currentLocation.x + GameConstants._dx[random_direction],
							  currentLocation.y + GameConstants._dy[random_direction]);
					  if (next == null || (next.terrain == 0 &&  !(next.location.x == loc2.x && next.location.y == loc2.y)))
						  break;
				  }

				  return new Move(ACTIONS[random_direction]);
			  }
		  }
	  default:
		  Util.debugMessage("move", "use random move");
		  int random_direction = 0;
		  int count = 0;
		  while(true) {
			  count++;
			  if (count > 1000)
				  break;
			  random_direction = rand.nextInt(7) + 1;  
			  Cell next = map.getCell(
					  currentLocation.x + GameConstants._dx[random_direction],
					  currentLocation.y + GameConstants._dy[random_direction]);
			  if (next == null || (next.terrain == 0 &&  !(next.location.x == loc2.x && next.location.y == loc2.y)))
				  break;
		  }

		  return new Move(ACTIONS[random_direction]);
	  }
  }
  

  public ArrayList<Cell> findUnsteppedCellTarget() {
    ArrayList<Cell> targets = new ArrayList<Cell>();
    Cell best_cell = null;
    double min_distance = Double.MAX_VALUE;
    for (Point p : map.getAllDiscoveredCoordinates()) {
      Cell c = map.getCell(p);
      if (c.claimed_distance > 0.5 && sp.getShortestDistance(p) < min_distance) {
        best_cell = c;
        min_distance = sp.getShortestDistance(p);
      }
    }
    if (best_cell != null)
      targets.add(best_cell);
    return targets;
  }

	public ArrayList<Cell> endGameTargets()
	{
		ArrayList<Cell> clist = new ArrayList<Cell>();
		Set<Point> sps = map.getAllDiscoveredCoordinates();
		//sp.updateShortestPath(current_location);
		
		// Let us iterator through all the discovered cells till now.
		if(sps!=null)
		{
			
			
			Iterator<Point> ip = sps.iterator();
			while(ip.hasNext())
			{
				Point p1 = ip.next();
				Cell ctest = map.getCell(p1);
				if(ctest.terrain == 0 && ctest.claimed_distance>0.5) // it has to be a un-stepped land cell
				{
				int totalnulls = 0;
				Set<Integer> ud = ctest.unexplored_directions; // how many un-explored regions
				
				
				Iterator iu = ud.iterator();
				while(iu.hasNext())
				{
					Integer i = (Integer)iu.next();
					switch(i)
					{
					case 1: {totalnulls += nullcells(ctest,1);break;}
					case 2: {totalnulls += nullcells(ctest,1);break;}
					case 3: {totalnulls += nullcells(ctest,2);break;}
					case 4: {totalnulls += nullcells(ctest,2);break;}
				
					case 5: {totalnulls += nullcells(ctest,3);break;}
					case 6: {totalnulls += nullcells(ctest,3);break;}
					case 7: {totalnulls += nullcells(ctest,4);break;}
					case 8: {totalnulls += nullcells(ctest,4);break;}
					
					}
					
					
				}
				ctest.nullvalue = totalnulls - (int)(sp.getShortestDistance(ctest.location)*0.5);
        clist.add(ctest);
				
				
				}// if ends
				
			}
		}

		
		
		
		Collections.sort(clist,new nullcompare());	
		// Let us print the first 5 values: 
		Util.debugMessage("null target", "\n N candidates are: ");
		for(int loop=0;loop<clist.size();loop++)
		{
			Util.debugMessage("null target", "\n C no (" + loop + ") = (" + clist.get(loop).location.x + "," + clist.get(loop).location.y + ") >> " + clist.get(loop).nullvalue);
		}
		
		return clist;
		
	}// my function ends
	
	
	public int nullcells(Cell c,int dirs)
	{
// 		This function return the number of cells in the direction mentioned
//		1 = up right
//		2 = down right
//		3 = down left
//		4 = up left
//		
// 		Current window is of size 3 x 5
		if(dirs == 1)
		{
			int nullcount=0;
			// x
			for(int loop1=0;loop1<4;loop1++)
			{
				//y
				for(int loop2=1;loop2<5;loop2++)
				{
					int xcor = c.location.x + loop1;
					int ycor = c.location.y - loop2;
					
					//if cells are padded, i dont know if this is imp
					//if(xcor<=map.getmin().x && xcor>=map.getmax().x && ycor<=map.getmin().y && ycor>=map.getmax().y)
					{
						Cell ctest = map.getCell(xcor, ycor);
						if(ctest == null)
						{
							nullcount++;
						}
					}
					
				}
			}
			
			return nullcount;
		}// case 1 ends
		
		if(dirs == 2)
		{
			int nullcount=0;
			// x
			for(int loop1=1;loop1<5;loop1++)
			{
				//y
				for(int loop2=0;loop2<4;loop2++)
				{
					int xcor = c.location.x + loop1;
					int ycor = c.location.y + loop2;
					//if(xcor<=map.getmin().x && xcor>=map.getmax().x && ycor<=map.getmin().y && ycor>=map.getmax().y)
					{
						Cell ctest = map.getCell(xcor, ycor);
						if(ctest == null)
						{
							nullcount++;
						}
					}
					
				}
			}
			
			return nullcount;
		}// case 2 ends
		
		if(dirs == 3)
		{
			int nullcount=0;
			// x
			for(int loop1=0;loop1<4;loop1++)
			{
				//y
				for(int loop2=1;loop2<5;loop2++)
				{
					int xcor = c.location.x - loop1;
					int ycor = c.location.y + loop2;
					//if(xcor<=map.getmin().x && xcor>=map.getmax().x && ycor<=map.getmin().y && ycor>=map.getmax().y)
					{
						Cell ctest = map.getCell(xcor, ycor);
						if(ctest == null)
						{
							nullcount++;
						}
					}
					
				}
			}
			
			return nullcount;
		}// case 3 ends
		
		if(dirs == 4)
		{
			int nullcount=0;
			// x
			for(int loop1=1;loop1<5;loop1++)
			{
				//y
				for(int loop2=0;loop2<4;loop2++)
				{
					int xcor = c.location.x - loop1;
					int ycor = c.location.y - loop2;
					//if(xcor<=map.getmin().x && xcor>=map.getmax().x && ycor<=map.getmin().y && ycor>=map.getmax().y)
					{
						Cell ctest = map.getCell(xcor, ycor);
						if(ctest == null)
						{
							nullcount++;
						}
					}
					
				}
			}
			
			return nullcount;
		}// case 1 ends
		
		
		return 1;
	}
	
	public String name() throws Exception {
		return "Syn Diego Conti";
	}
}